'use strict';
const extend = require('extend');
const cliCursor = require('cli-cursor');
const cliSpinners = require('cli-spinners');
const logSymbols = require('log-symbols');

class Ora {
    constructor(options) {
        if (typeof options === 'string') {
            options = {
                text: options
            };
        }

        this.options = extend(true, {
            text: '',
            color: 'cyan',
            stream: process.stderr
        }, options);

        const sp = this.options.spinner;
        this.spinner = typeof sp === 'object'
            ? sp
            : (process.platform === 'win32'
                ? cliSpinners.line
                : (cliSpinners[sp] || cliSpinners.dots)); // eslint-disable-line no-nested-ternary

        if (this.spinner.frames === undefined) {
            throw new Error('Spinner must define `frames`');
        }

        this.text = this.options.text;
        this.color = this.options.color;
        this.interval = this.options.interval || this.spinner.interval || 100;
        this.stream = this.options.stream;
        this.id = null;
        this.frameIndex = 0;
        this.enabled = this.options.enabled || ((this.stream && this.stream.isTTY) && !process.env.CI);
    }
    frame() {
        const frames = this.spinner.frames;
        let frame = frames[this.frameIndex];

        if (this.color) {
            frame = frame[this.color];
        }

        this.frameIndex = ++this.frameIndex % frames.length;

        return frame + ' ' + this.text;
    }
    clear() {
        if (!this.enabled) {
            return this;
        }

        this.stream.clearLine();
        this.stream.cursorTo(0);

        return this;
    }
    render() {
        this.clear();
        this.stream.write(this.frame());

        return this;
    }
    start() {
        if (!this.enabled || this.id) {
            return this;
        }

        cliCursor.hide();
        this.render();
        this.id = setInterval(this.render.bind(this), this.interval);

        return this;
    }
    stop() {
        if (!this.enabled) {
            return this;
        }

        clearInterval(this.id);
        this.id = null;
        this.frameIndex = 0;
        this.clear();
        cliCursor.show();

        return this;
    }
    succeed() {
        return this.stopAndPersist(logSymbols.success);
    }
    fail() {
        return this.stopAndPersist(logSymbols.error);
    }
    stopAndPersist(symbol) {
        this.stop();
        this.stream.write(`${symbol || ' '} ${this.text}\n`);

        return this;
    }
}

module.exports = function(opts) {
    return new Ora(opts);
};
